/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * This is an implementation of an early-draft specification developed under the Java * Community Process (JCP) and is made available for testing and evaluation purposes * only. The code is not compatible with any specification of the JCP. * * Contributors: * IBM Corporation - initial API and implementation * Jesper S. Møller - bug 422029: [1.8] Enable debug evaluation support for default methods *******************************************************************************/ package org.eclipse.jdt.debug.testplugin; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.zip.ZipFile; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.core.ClasspathEntry; import org.eclipse.ui.dialogs.IOverwriteQuery; import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider; import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider; import org.eclipse.ui.wizards.datatransfer.ImportOperation; import org.eclipse.ui.wizards.datatransfer.ZipFileStructureProvider; /** * Helper methods to set up a IJavaProject. */ public class JavaProjectHelper { public static final String SRC_DIR = "src"; public static final String BIN_DIR = "bin"; public static final String J2SE_1_4_EE_NAME = "J2SE-1.4"; public static final String J2SE_1_5_EE_NAME = "J2SE-1.5"; public static final String JAVA_SE_1_6_EE_NAME = "JavaSE-1.6"; public static final String JAVA_SE_1_7_EE_NAME = "JavaSE-1.7"; public static final String JAVA_SE_1_8_EE_NAME = "JavaSE-1.8"; /** * path to the test src for 'testprograms' */ public static final IPath TEST_SRC_DIR= new Path("testprograms"); /** * path to the 1.5 test source */ public static final IPath TEST_1_5_SRC_DIR= new Path("testsource-j2se-1.5"); /** * path to the 1.7 test source */ public static final IPath TEST_1_7_SRC_DIR= new Path("java7"); /** * path to the 1.8 test source */ public static final IPath TEST_1_8_SRC_DIR= new Path("java8"); /** * path to the compiler error java file */ public static final IPath TEST_COMPILE_ERROR = new Path("testresources/CompilationError.java"); public static final String JRE_CONTAINER_NAME = "org.eclipse.jdt.launching.JRE_CONTAINER"; /** * Returns if the currently running VM is version compatible with Java 8 * * @return <code>true</code> if a Java 8 (or greater) VM is running <code>false</code> otherwise */ public static boolean isJava8Compatible() { return isCompatible(8); } /** * Returns if the currently running VM is version compatible with Java 7 * * @return <code>true</code> if a Java 7 (or greater) VM is running <code>false</code> otherwise */ public static boolean isJava7Compatible() { return isCompatible(7); } /** * Returns if the currently running VM is version compatible with Java 6 * * @return <code>true</code> if a Java 6 (or greater) VM is running <code>false</code> otherwise */ public static boolean isJava6Compatible() { return isCompatible(6); } /** * Returns if the currently running VM is version compatible with Java 5 * * @return <code>true</code> if a Java 5 (or greater) VM is running <code>false</code> otherwise */ public static boolean isJava5Compatible() { return isCompatible(5); } /** * Returns if the current running system is compatible with the given Java minor version * * @param ver the version to test - either 4, 5, 6, 7 or 8 * @return <code>true</code> if compatible <code>false</code> otherwise */ static boolean isCompatible(int ver) { String version = System.getProperty("java.specification.version"); if (version != null) { String[] nums = version.split("\\."); if (nums.length == 2) { try { int major = Integer.parseInt(nums[0]); int minor = Integer.parseInt(nums[1]); if (major >= 1) { if (minor >= ver) { return true; } } } catch (NumberFormatException e) { } } } return false; } /** * Creates a new {@link IProject} with the given name unless the project already exists. If it already exists * the project is refreshed and opened (if closed) * * @param pname the desired name for the project * @return the new {@link IProject} handle * @throws CoreException */ public static IProject createProject(String pname) throws CoreException { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IProject project = root.getProject(pname); if (!project.exists()) { project.create(null); } else { project.refreshLocal(IResource.DEPTH_INFINITE, null); } if (!project.isOpen()) { project.open(null); } return project; } /** * creates a java project with the specified name and output folder * @param projectName * @param binFolderName * @return a new java project * @throws CoreException */ public static IJavaProject createJavaProject(String projectName, String binFolderName) throws CoreException { IProject project = createProject(projectName); IPath outputLocation; if (binFolderName != null && binFolderName.length() > 0) { IFolder binFolder= project.getFolder(binFolderName); if (!binFolder.exists()) { binFolder.create(false, true, null); } outputLocation= binFolder.getFullPath(); } else { outputLocation= project.getFullPath(); } if (!project.hasNature(JavaCore.NATURE_ID)) { addNatureToProject(project, JavaCore.NATURE_ID, null); } IJavaProject jproject= JavaCore.create(project); jproject.setOutputLocation(outputLocation, null); jproject.setRawClasspath(new IClasspathEntry[0], null); return jproject; } /** * Creates a new Java project with the specified name * @param projectName * @return a new java project with the specified name * @throws CoreException */ public static IJavaProject createJavaProject(String projectName) throws CoreException { IProject project = createProject(projectName); if (!project.hasNature(JavaCore.NATURE_ID)) { addNatureToProject(project, JavaCore.NATURE_ID, null); } IJavaProject jproject= JavaCore.create(project); jproject.setRawClasspath(new IClasspathEntry[0], null); return jproject; } /** * deletes a java project * @param jproject * @throws CoreException */ public static void delete(IJavaProject jproject) throws CoreException { jproject.setRawClasspath(new ClasspathEntry[0], jproject.getProject().getFullPath(), null); jproject.getProject().delete(true, true, null); } /** * Adds a new source container specified by the container name to the source path of the specified project * @param jproject * @param containerName * @return the package fragment root of the container name * @throws CoreException */ public static IPackageFragmentRoot addSourceContainer(IJavaProject jproject, String containerName) throws CoreException { IProject project= jproject.getProject(); IContainer container= null; if (containerName == null || containerName.length() == 0) { container= project; } else { IFolder folder= project.getFolder(containerName); if (!folder.exists()) { folder.create(false, true, null); } container= folder; } IPackageFragmentRoot root= jproject.getPackageFragmentRoot(container); IClasspathEntry cpe= JavaCore.newSourceEntry(root.getPath()); addToClasspath(jproject, cpe); return root; } /** * Adds a source container to a IJavaProject. * @param jproject * @param containerName * @param outputName * @return the package fragment root of the new source container * @throws CoreException */ public static IPackageFragmentRoot addSourceContainer(IJavaProject jproject, String containerName, String outputName) throws CoreException { IProject project= jproject.getProject(); IContainer container= null; if (containerName == null || containerName.length() == 0) { container= project; } else { IFolder folder= project.getFolder(containerName); if (!folder.exists()) { folder.create(false, true, null); } container= folder; } IPackageFragmentRoot root= jproject.getPackageFragmentRoot(container); IFolder output = null; if (outputName!= null) { output = project.getFolder(outputName); if (!output.exists()) { output.create(false, true, null); } } IClasspathEntry cpe= JavaCore.newSourceEntry(root.getPath(), new IPath[0], output.getFullPath()); addToClasspath(jproject, cpe); return root; } /** * Adds a source container to a IJavaProject and imports all files contained * in the given Zip file. * @param jproject * @param containerName * @param zipFile * @return the package fragment root of the new source container * @throws InvocationTargetException * @throws CoreException */ public static IPackageFragmentRoot addSourceContainerWithImport(IJavaProject jproject, String containerName, ZipFile zipFile) throws InvocationTargetException, CoreException { IPackageFragmentRoot root= addSourceContainer(jproject, containerName); importFilesFromZip(zipFile, root.getPath(), null); return root; } /** * Removes a source folder from a IJavaProject. * @param jproject * @param containerName * @throws CoreException */ public static void removeSourceContainer(IJavaProject jproject, String containerName) throws CoreException { IFolder folder= jproject.getProject().getFolder(containerName); removeFromClasspath(jproject, folder.getFullPath()); folder.delete(true, null); } /** * Adds a library entry to a IJavaProject. * @param jproject * @param path * @return the package fragment root of the new library * @throws JavaModelException */ public static IPackageFragmentRoot addLibrary(IJavaProject jproject, IPath path) throws JavaModelException { return addLibrary(jproject, path, null, null); } /** * Adds a library entry with source attchment to a IJavaProject. * @param jproject * @param path * @param sourceAttachPath * @param sourceAttachRoot * @return the package fragment root of the new library * @throws JavaModelException */ public static IPackageFragmentRoot addLibrary(IJavaProject jproject, IPath path, IPath sourceAttachPath, IPath sourceAttachRoot) throws JavaModelException { IClasspathEntry cpe= JavaCore.newLibraryEntry(path, sourceAttachPath, sourceAttachRoot); addToClasspath(jproject, cpe); return jproject.getPackageFragmentRoot(path.toString()); } /** * Copies the library into the project and adds it as library entry. * @param jproject * @param jarPath * @param sourceAttachPath * @param sourceAttachRoot * @return the package fragment root of the new library * @throws IOException * @throws CoreException */ public static IPackageFragmentRoot addLibraryWithImport(IJavaProject jproject, IPath jarPath, IPath sourceAttachPath, IPath sourceAttachRoot) throws IOException, CoreException { IProject project= jproject.getProject(); IFile newFile= project.getFile(jarPath.lastSegment()); try (InputStream inputStream = new FileInputStream(jarPath.toFile())) { newFile.create(inputStream, true, null); } return addLibrary(jproject, newFile.getFullPath(), sourceAttachPath, sourceAttachRoot); } /** * Adds a variable entry with source attachment to a IJavaProject. * Can return null if variable can not be resolved. * @param jproject * @param path * @param sourceAttachPath * @param sourceAttachRoot * @return the package fragment root of the new variable entry * @throws JavaModelException */ public static IPackageFragmentRoot addVariableEntry(IJavaProject jproject, IPath path, IPath sourceAttachPath, IPath sourceAttachRoot) throws JavaModelException { IClasspathEntry cpe= JavaCore.newVariableEntry(path, sourceAttachPath, sourceAttachRoot); addToClasspath(jproject, cpe); IPath resolvedPath= JavaCore.getResolvedVariablePath(path); if (resolvedPath != null) { return jproject.getPackageFragmentRoot(resolvedPath.toString()); } return null; } /** * Adds a container entry to the specified java project * @param project * @param container * @throws JavaModelException */ public static void addContainerEntry(IJavaProject project, IPath container) throws JavaModelException { IClasspathEntry cpe = JavaCore.newContainerEntry(container, false); addToClasspath(project, cpe); } /** * Sets the given compiler compliance on the given {@link IJavaProject} * <br><br> * See {@link JavaCore#VERSION_1_4}, {@link JavaCore#VERSION_1_5}, {@link JavaCore#VERSION_1_6}, * {@link JavaCore#VERSION_1_7} and {@link JavaCore#VERSION_1_8} for more information on accepted compliances * * @param project * @param compliance */ public static void setCompliance(IJavaProject project, String compliance) { Map<String, String> map = JavaCore.getOptions(); map.put(JavaCore.COMPILER_COMPLIANCE, compliance); map.put(JavaCore.COMPILER_SOURCE, compliance); map.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, compliance); project.setOptions(map); } /** * Updates the compiler compliance project setting for the given project to match the given EE. * I.e. J2SE-1.5 will set a 1.5 compliance for the compiler and the source level. * @param project * @param ee */ public static void updateCompliance(IJavaProject project, String ee) { if(J2SE_1_4_EE_NAME.equals(ee)) { setCompliance(project, JavaCore.VERSION_1_4); } else if(J2SE_1_5_EE_NAME.equals(ee)) { setCompliance(project, JavaCore.VERSION_1_5); } else if(JAVA_SE_1_7_EE_NAME.equals(ee)) { setCompliance(project, JavaCore.VERSION_1_7); } else if(JAVA_SE_1_8_EE_NAME.equals(ee)) { setCompliance(project, JavaCore.VERSION_1_8); } } /** * Adds a required project entry. * @param jproject * @param required * @throws JavaModelException */ public static void addRequiredProject(IJavaProject jproject, IJavaProject required) throws JavaModelException { IClasspathEntry cpe= JavaCore.newProjectEntry(required.getProject().getFullPath()); addToClasspath(jproject, cpe); } /** * Removes a specified path form the specified java project * @param jproject * @param path * @throws JavaModelException */ public static void removeFromClasspath(IJavaProject jproject, IPath path) throws JavaModelException { IClasspathEntry[] oldEntries= jproject.getRawClasspath(); int nEntries= oldEntries.length; ArrayList<IClasspathEntry> list= new ArrayList<IClasspathEntry>(nEntries); for (int i= 0 ; i < nEntries ; i++) { IClasspathEntry curr= oldEntries[i]; if (!path.equals(curr.getPath())) { list.add(curr); } } IClasspathEntry[] newEntries= list.toArray(new IClasspathEntry[list.size()]); jproject.setRawClasspath(newEntries, null); } /** * Adds the specified classpath entry to the specified java project * @param jproject * @param cpe * @throws JavaModelException */ public static void addToClasspath(IJavaProject jproject, IClasspathEntry cpe) throws JavaModelException { IClasspathEntry[] oldEntries= jproject.getRawClasspath(); ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(oldEntries.length); for (int i= 0; i < oldEntries.length; i++) { if (oldEntries[i].equals(cpe)) { return; } IPath oldpath = oldEntries[i].getPath(); if(JRE_CONTAINER_NAME.equals(oldpath.segment(0)) && JRE_CONTAINER_NAME.equals(cpe.getPath().segment(0))) { continue; } entries.add(oldEntries[i]); } entries.add(cpe); jproject.setRawClasspath(entries.toArray(new IClasspathEntry[entries.size()]), null); } /** * Adds the specified nature to the specified project * @param proj * @param natureId * @param monitor * @throws CoreException */ private static void addNatureToProject(IProject proj, String natureId, IProgressMonitor monitor) throws CoreException { IProjectDescription description = proj.getDescription(); String[] prevNatures= description.getNatureIds(); String[] newNatures= new String[prevNatures.length + 1]; System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length); newNatures[prevNatures.length]= natureId; description.setNatureIds(newNatures); proj.setDescription(description, monitor); } /** * Imports files from the specified zip to the specified destination * @param srcZipFile * @param destPath * @param monitor * @throws InvocationTargetException */ private static void importFilesFromZip(ZipFile srcZipFile, IPath destPath, IProgressMonitor monitor) throws InvocationTargetException { ZipFileStructureProvider structureProvider= new ZipFileStructureProvider(srcZipFile); try { ImportOperation op= new ImportOperation(destPath, structureProvider.getRoot(), structureProvider, new ImportOverwriteQuery()); op.run(monitor); } catch (InterruptedException e) { // should not happen } } /** * Imports files from the specified root dir into the specified path * @param rootDir * @param destPath * @param monitor * @throws InvocationTargetException * @throws IOException */ public static void importFilesFromDirectory(File rootDir, IPath destPath, IProgressMonitor monitor) throws InvocationTargetException, IOException { IImportStructureProvider structureProvider = FileSystemStructureProvider.INSTANCE; List<File> files = new ArrayList<>(100); addJavaFiles(rootDir, files); try { ImportOperation op= new ImportOperation(destPath, rootDir, structureProvider, new ImportOverwriteQuery(), files); op.setCreateContainerStructure(false); op.run(monitor); IStatus status = op.getStatus(); if (!status.isOK()) { CoreException e = new CoreException(status); throw new InvocationTargetException(e, "Import operation encountered problems"); } } catch (InterruptedException e) { throw new InvocationTargetException(e, "Interrupted during files import"); } } /** * Imports the specified file into the specified path * @param file * @param destPath * @param monitor * @throws InvocationTargetException */ public static void importFile(File file, IPath destPath, IProgressMonitor monitor) throws InvocationTargetException { IImportStructureProvider structureProvider = FileSystemStructureProvider.INSTANCE; List<File> files = new ArrayList<File>(1); files.add(file); try { ImportOperation op= new ImportOperation(destPath, file.getParentFile(), structureProvider, new ImportOverwriteQuery(), files); op.setCreateContainerStructure(false); op.run(monitor); } catch (InterruptedException e) { // should not happen } } /** * Recursively adds files from the specified dir to the provided list * @param dir * @param collection * @throws IOException */ private static void addJavaFiles(File dir, List<File> collection) throws IOException { File[] files = dir.listFiles(); if(files != null) { List<File> subDirs = new ArrayList<File>(2); for (int i = 0; i < files.length; i++) { if (files[i].isFile()) { collection.add(files[i]); } else if (files[i].isDirectory() && files[i].getName().indexOf("CVS") < 0) { subDirs.add(files[i]); } } Iterator<File> iter = subDirs.iterator(); while (iter.hasNext()) { File subDir = iter.next(); addJavaFiles(subDir, collection); } } } /** * Static class for an <code>IOverwriteQuery</code> implementation */ private static class ImportOverwriteQuery implements IOverwriteQuery { /** * @see org.eclipse.ui.dialogs.IOverwriteQuery#queryOverwrite(java.lang.String) */ @Override public String queryOverwrite(String file) { return ALL; } } }